{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import tensorflow as tf\n",
    "import scipy.io\n",
    "\n",
    "import os, re\n",
    "\n",
    "import claude.utils as cu\n",
    "import claude.claudeflow.autoencoder as ae\n",
    "import claude.claudeflow.helper as cfh\n",
    "import claude.claudeflow.training as cft"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from random import randrange\n",
    "seed = randrange(1e5)\n",
    "tf.set_random_seed(seed)\n",
    "np.random.seed(seed)\n",
    "\n",
    "summaries_dir = 'MINE'\n",
    "os.makedirs(summaries_dir, exist_ok=True)\n",
    "\n",
    "# Parameters\n",
    "# Channel Parameters\n",
    "chParam = cu.AttrDict()\n",
    "chParam.M = 16\n",
    "if chParam.M == 16:\n",
    "    chParam.SNR_db = 10\n",
    "elif chParam.M == 64:\n",
    "    chParam.SNR_db = 18\n",
    "else:\n",
    "    chParam.SNR_db = 22\n",
    "\n",
    "# Auto-Encoder Parameters\n",
    "aeParam = cu.AttrDict()\n",
    "aeParam.constellationDim = 2\n",
    "aeParam.constellationOrder = chParam.M\n",
    "aeParam.nLayers     = 2\n",
    "aeParam.nHidden     = 32\n",
    "aeParam.nLayersMINE = 2\n",
    "aeParam.nHiddenMINE = 20\n",
    "aeParam.activation  = tf.nn.relu\n",
    "aeParam.dtype       = tf.float32\n",
    "aeParam.cpx_dtype   = tf.complex64\n",
    "\n",
    "# Training Parameters\n",
    "trainingParam = cu.AttrDict()\n",
    "trainingParam.MINE_learningRate = 0.0005\n",
    "trainingParam.MINE_iterations   = 1000\n",
    "trainingParam.MINE_batchSize    = 200\n",
    "\n",
    "trainingParam.encoder_iterations   = [1000, 10000, 10000]\n",
    "trainingParam.encoder_batchSize    = [100, 100, 1000]\n",
    "trainingParam.encoder_learningRate = [0.01, 0.01, 0.001]\n",
    "\n",
    "trainingParam.decoder_iterations   = 1000\n",
    "trainingParam.decoder_batchSize    = 16 * chParam.M\n",
    "trainingParam.decoder_learningRate = 0.001\n",
    "\n",
    "# TF constants\n",
    "one = tf.constant(1, aeParam.dtype)\n",
    "two = tf.constant(2,aeParam.dtype)\n",
    "PI = tf.constant(np.pi,aeParam.dtype)\n",
    "\n",
    "twoZeroCpx = tf.constant(2, aeParam.cpx_dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# channel implemented with pass through gradient, see discussion here:\n",
    "# https://github.com/Fritschek/Wireless_encoding_with_MI_estimation/issues/1\n",
    "@tf.custom_gradient\n",
    "def channel(x):\n",
    "    SNR_db = tf.constant(chParam.SNR_db, dtype=aeParam.dtype)\n",
    "    sigma2 = one / cfh.dB2lin(SNR_db, 'dB')\n",
    "    noise_cpx = tf.complex(tf.random_normal(shape=tf.shape(x), dtype=aeParam.dtype),\n",
    "                           tf.random_normal(shape=tf.shape(x), dtype=aeParam.dtype))\n",
    "    noise = tf.cast(tf.sqrt(sigma2), aeParam.cpx_dtype)\\\n",
    "            * tf.rsqrt(twoZeroCpx) * noise_cpx\n",
    "    y = x + noise\n",
    "    def grad(dy):\n",
    "        return dy\n",
    "    return y, grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def tx(X):\n",
    "    # Tx Graph\n",
    "    x_vec, x_seed = ae.encoder(X, aeParam, name='encoder')\n",
    "    x = cfh.real2complex(x_vec)\n",
    "\n",
    "    # Channel Graph\n",
    "    y = channel(x)\n",
    "\n",
    "    y_vec = cfh.complex2real(y)\n",
    "    \n",
    "    return x_vec, y_vec, x, y, x_seed\n",
    "\n",
    "def MINE(x_vec_joint, y_vec_joint, y_vec_marginal):\n",
    "    inp_joint = tf.concat((x_vec_joint, y_vec_joint), axis=-1)\n",
    "    inp_marginal = tf.concat((x_vec_joint, y_vec_marginal), axis=-1)\n",
    "    out_joint = ae._encoder(inp_joint,\n",
    "                            aeParam.nHiddenMINE,\n",
    "                            aeParam.nLayersMINE,\n",
    "                            aeParam.activation,\n",
    "                            kernel_initializer=tf.random_normal_initializer(stddev=0.05),\n",
    "                            nOutput=1,\n",
    "                            name='MINE')\n",
    "    out_marginal = ae._encoder(inp_marginal,\n",
    "                               aeParam.nHiddenMINE,\n",
    "                               aeParam.nLayersMINE,\n",
    "                               aeParam.activation,\n",
    "                               kernel_initializer=tf.random_normal_initializer(stddev=0.05),\n",
    "                               nOutput=1,\n",
    "                               name='MINE')\n",
    "\n",
    "    MI_est = tf.reduce_mean(out_joint) - tf.log(tf.reduce_mean(tf.exp(out_marginal)))\n",
    "    \n",
    "    return MI_est"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Logging before flag parsing goes to stderr.\n",
      "W0324 20:21:20.661957 140708513933120 deprecation.py:506] From /home/rasmus/.conda/envs/claudeOnline/lib/python3.6/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Call initializer instance with the dtype argument instead of passing it to the constructor\n",
      "W0324 20:21:22.868181 140708513933120 lazy_loader.py:50] \n",
      "The TensorFlow contrib module will not be included in TensorFlow 2.0.\n",
      "For more information, please see:\n",
      "  * https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md\n",
      "  * https://github.com/tensorflow/addons\n",
      "  * https://github.com/tensorflow/io (for I/O related ops)\n",
      "If you depend on functionality not listed there, please file an issue.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "X_joint = tf.placeholder(aeParam.dtype, shape=(None, chParam.M))\n",
    "X_marginal = tf.placeholder(aeParam.dtype, shape=(None, chParam.M))\n",
    "\n",
    "x_vec_joint, y_vec_joint, x_joint, y_joint, x_seed = tx(X_joint)\n",
    "_, y_vec_marginal, _, _, _ = tx(X_marginal)\n",
    "\n",
    "constellation = cfh.real2complex(x_seed)\n",
    "MI_est = MINE(x_vec_joint, y_vec_joint, y_vec_marginal)\n",
    "\n",
    "decoder = ae.decoder(y_vec_joint, aeParam, fromComplex=False)\n",
    "loss = tf.nn.softmax_cross_entropy_with_logits_v2(labels=X_joint, logits=decoder)\n",
    "\n",
    "gaussian_MI = cfh.gaussianMI(x_joint, y_joint, cfh.real2complex(x_seed), chParam.M, dtype=aeParam.dtype)\n",
    "Px = tf.constant( 1/chParam.M, aeParam.dtype )\n",
    "softmax_MI = cfh.softmaxMI(tf.nn.softmax(decoder), X_joint, Px)\n",
    "\n",
    "metricsDict = {'softmax_MI_metric':softmax_MI, 'gaussian_MI_metric':gaussian_MI}\n",
    "meanMetricOpsDict, updateOps, resetOps = cft.create_mean_metrics(metricsDict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "summary_MINE = tf.summary.scalar('MINE_MI', MI_est)\n",
    "summary_encoder = tf.summary.scalar('encoder_MI', MI_est)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0324 20:21:23.438755 140708513933120 deprecation.py:323] From /home/rasmus/.conda/envs/claudeOnline/lib/python3.6/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.where in 2.0, which has the same broadcast rule as np.where\n"
     ]
    }
   ],
   "source": [
    "MINE_vars = [var for var in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES) if 'MINE' in var.name]\n",
    "MINE_optimizer = tf.train.AdamOptimizer(learning_rate=trainingParam.MINE_learningRate)\n",
    "MINE_optimizer = MINE_optimizer.minimize(-MI_est, var_list=MINE_vars)\n",
    "\n",
    "encoder_learning_rate = tf.placeholder(tf.float32, shape=())\n",
    "encoder_vars = [var for var in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES) if 'encoder' in var.name]\n",
    "encoder_optimizer = tf.train.AdamOptimizer(learning_rate=encoder_learning_rate)\n",
    "encoder_optimizer = encoder_optimizer.minimize(-MI_est, var_list=encoder_vars)\n",
    "\n",
    "decoder_vars = [var for var in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES) if 'decoder' in var.name]\n",
    "decoder_optimizer = tf.train.AdamOptimizer(learning_rate=trainingParam.decoder_learningRate)\n",
    "decoder_optimizer = decoder_optimizer.minimize(loss, var_list=decoder_vars)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TRAINING\n",
    "init = tf.global_variables_initializer()\n",
    "sess = tf.Session()\n",
    "\n",
    "writer = tf.summary.FileWriter(summaries_dir + '/MINE', sess.graph)\n",
    "\n",
    "sess.run(init)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "encoder_c = 1\n",
    "MINE_c = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sample(batchSize):\n",
    "    data_joint, _, _ = cu.hotOnes(batchSize,(1,0),chParam.M)\n",
    "    data_marginal, _, _ = cu.hotOnes(batchSize,(1,0),chParam.M)\n",
    "    return data_joint, data_marginal\n",
    "\n",
    "def MINE_train():\n",
    "    global MINE_c\n",
    "    for ii in range(1, trainingParam.MINE_iterations+1):\n",
    "        data_joint, data_marginal = sample(trainingParam.MINE_batchSize)\n",
    "        feedDict = {X_joint: data_joint, X_marginal: data_marginal}\n",
    "        [_, out_summary_MINE] = sess.run([MINE_optimizer, summary_MINE], feed_dict=feedDict)\n",
    "        writer.add_summary(out_summary_MINE, MINE_c)\n",
    "        MINE_c += 1\n",
    "\n",
    "def encoder_train(iterations, batchSize, learning_rate):\n",
    "    global encoder_c\n",
    "    trainMINEnow = iterations//10\n",
    "    for ii in range(1, iterations+1):\n",
    "        data_joint, data_marginal = sample(batchSize)\n",
    "        feedDict = {X_joint: data_joint, X_marginal: data_marginal, encoder_learning_rate: learning_rate}\n",
    "        [_, out_summary_encoder] = sess.run([encoder_optimizer, summary_encoder], feed_dict=feedDict)\n",
    "        writer.add_summary(out_summary_encoder, encoder_c)\n",
    "        encoder_c += 1\n",
    "\n",
    "        if ii % trainMINEnow == 0:\n",
    "            MINE_train()\n",
    "            \n",
    "def decoder_train(iterations, batchSize, learning_rate):\n",
    "    for ii in range(1, iterations+1):\n",
    "        data_joint, data_marginal = sample(batchSize)\n",
    "        feedDict = {X_joint: data_joint, X_marginal: data_marginal}\n",
    "        sess.run(decoder_optimizer, feed_dict=feedDict)\n",
    "    \n",
    "    sess.run(resetOps)\n",
    "    for ii in range(1, iterations+1):\n",
    "        data_joint, data_marginal = sample(batchSize)\n",
    "        feedDict = {X_joint: data_joint, X_marginal: data_marginal}\n",
    "        sess.run(updateOps, feed_dict=feedDict)\n",
    "    out_meanMetrics = sess.run(list(meanMetricOpsDict.values()), feed_dict=feedDict)\n",
    "        \n",
    "    return {'softmaxMI': out_meanMetrics[0], 'gaussianMI': out_meanMetrics[1]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LOOP_TRAIN 1/3\n",
      "LOOP_TRAIN 2/3\n",
      "LOOP_TRAIN 3/3\n"
     ]
    }
   ],
   "source": [
    "# init training\n",
    "MINE_train()\n",
    "\n",
    "# encoder/MINE training\n",
    "encoder_train_list = zip(trainingParam.encoder_iterations,\n",
    "                         trainingParam.encoder_batchSize,\n",
    "                         trainingParam.encoder_learningRate)\n",
    "\n",
    "MINE_count = 1\n",
    "encoder_count = 1\n",
    "for idx,(it,bs,lr) in enumerate(encoder_train_list):\n",
    "    print('LOOP_TRAIN {}/{}'.format(idx+1, len(trainingParam.encoder_iterations)))\n",
    "    encoder_train(it, bs, lr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "np_constellation = sess.run(constellation)\n",
    "lim_ = 1.5\n",
    "plt.plot(np.real(np_constellation), np.imag(np_constellation), '.');\n",
    "plt.axis('square');\n",
    "plt.xlim(-lim_,lim_);\n",
    "plt.ylim(-lim_,lim_);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "data_joint, data_marginal = sample(trainingParam.MINE_batchSize)\n",
    "feedDict = {X_joint: data_joint, X_marginal: data_marginal}\n",
    "np_y_joint = sess.run(y_joint, feed_dict=feedDict)\n",
    "lim_ = 1.5\n",
    "plt.plot(np.real(np_y_joint), np.imag(np_y_joint), '.');\n",
    "plt.plot(np.real(np_constellation), np.imag(np_constellation), 'x');\n",
    "plt.axis('square');\n",
    "plt.xlim(-lim_,lim_);\n",
    "plt.ylim(-lim_,lim_);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'softmaxMI': 3.2269764, 'gaussianMI': 3.2069335}\n"
     ]
    }
   ],
   "source": [
    "finalMI_ish = decoder_train(trainingParam.decoder_iterations, trainingParam.decoder_batchSize, trainingParam.decoder_learningRate)\n",
    "print(finalMI_ish)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "SNR_db = np.arange(0, 30, 0.1)\n",
    "C = np.log2(1 + cu.dB2lin(SNR_db, dBtype='dB'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(SNR_db, C)\n",
    "plt.plot(chParam.SNR_db, finalMI_ish['gaussianMI'], 'x')\n",
    "plt.plot(chParam.SNR_db, finalMI_ish['softmaxMI'], 'x')\n",
    "plt.xlabel('SNR [dB]')\n",
    "plt.ylabel('MI')\n",
    "plt.grid(True)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
